package com.xyht.sca_s.student_manage_system.modules.questionnaire.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaban.analysis.jieba.JiebaSegmenter;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.questionnaire.entity.*;
import com.xyht.sca_s.student_manage_system.modules.questionnaire.entity.resp.*;
import com.xyht.sca_s.student_manage_system.modules.questionnaire.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.questionnaire.service.SmsQuestionnaireAnalysisService;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.questionnaire.constant.CommonConstant.OPTION_ANALYSIS_INPUT_LIMIT;
import static com.xyht.sca_s.student_manage_system.modules.questionnaire.constant.TopicTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.questionnaire.constant.TopicTypeRateConstant.*;

/**
 * <p>
 * 数据分析 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-02-08
 */
@Service
public class SmsQuestionnaireAnalysisServiceImpl extends ServiceImpl<SmsQuestionnaireAnalysisMapper, SmsQuestionnaireAnalysis> implements SmsQuestionnaireAnalysisService {
    @Autowired
    private SmsQuestionnaireMapper smsQuestionnaireMapper;
    @Autowired
    private SmsQuestionnaireTopicMapper smsQuestionnaireTopicMapper;
    @Autowired
    private SmsQuestionnaireOptionMapper smsQuestionnaireOptionMapper;
    @Autowired
    private SmsQuestionnaireConfirmMapper smsQuestionnaireConfirmMapper;
    @Autowired
    private SmsQuestionnaireAnalysisMapper smsQuestionnaireAnalysisMapper;


    @Override
    public ResponseResult getFormData(String ques_id, String bg_date, String end_date) {
        if (isNullOrEmpty(ques_id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        Date bgDate = null;
        Date endDate = null;
        if (!isNullOrEmpty(bg_date)) {
            bgDate = TimeUtil.StringtoDate(bg_date);
        }
        if (!isNullOrEmpty(end_date)) {
            endDate = TimeUtil.StringtoDate(end_date);
        }

        SmsQuestionnaire smsQuestionnaire = smsQuestionnaireMapper.selectById(ques_id);
        if (smsQuestionnaire == null) {
            return CommonResult.failed(CommonCodeEnum.QUESTIONNAIRE_NOT_EXIST);
        }

        SmsQuestionnaireAnalysisResp smsQuestionnaireAnalysisResp = new SmsQuestionnaireAnalysisResp();
        BeanUtils.copyProperties(smsQuestionnaire, smsQuestionnaireAnalysisResp);

        List<SmsQuestionnaireConfirm> smsQuestionnaireConfirmList = smsQuestionnaireConfirmMapper.selectList(new QueryWrapper<SmsQuestionnaireConfirm>()
                .lambda()
                .eq(SmsQuestionnaireConfirm::getQuesId, ques_id));
        if (smsQuestionnaireConfirmList == null || smsQuestionnaireConfirmList.size() < 1){
            return CommonResult.success(smsQuestionnaireAnalysisResp);
        }

        //获取题
        List<SmsQuestionnaireTopic> topicList = smsQuestionnaireTopicMapper.selectList(new QueryWrapper<SmsQuestionnaireTopic>()
                .lambda()
                .eq(SmsQuestionnaireTopic::getQuesId, ques_id)
                .orderByAsc(SmsQuestionnaireTopic::getSort));

        //遍历题型数据
        List<SmsQuestionnaireAnalysisTopicResp> analysisTopicRespList = new ArrayList<>();
        for (SmsQuestionnaireTopic topic : topicList) {
            SmsQuestionnaireAnalysisTopicResp analysisTopicResp = new SmsQuestionnaireAnalysisTopicResp();
            BeanUtils.copyProperties(topic, analysisTopicResp);

            //获取问卷访问次数
            Integer times = smsQuestionnaireAnalysisMapper.getUserIDBySearchStrCount(ques_id, topic.getId(), null,
                    null, null, null, null);
            if (times == null) {
                times = 0;
            }
            analysisTopicResp.setTimes(times);

            List<SmsQuestionnaireOption> optionList = smsQuestionnaireOptionMapper.selectList(new QueryWrapper<SmsQuestionnaireOption>()
                    .lambda()
                    .eq(SmsQuestionnaireOption::getTopicId, topic.getId())
                    .orderByAsc(SmsQuestionnaireOption::getSort));

            QueryWrapper<SmsQuestionnaireConfirm> totalQuestionnaireConfirm = new QueryWrapper<>();
            totalQuestionnaireConfirm
                    .lambda()
                    .eq(SmsQuestionnaireConfirm::getTopicId, topic.getId());
            if (bgDate != null) {
                totalQuestionnaireConfirm.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
            }
            if (endDate != null) {
                totalQuestionnaireConfirm.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
            }

            Integer totalOptionCount = smsQuestionnaireConfirmMapper.selectCount(totalQuestionnaireConfirm);

            List<SmsQuestionnaireAnalysisOptionResp> analysisOptionRespList = new ArrayList<>();
            for (SmsQuestionnaireOption option : optionList) {
                SmsQuestionnaireAnalysisOptionResp analysisOptionResp = new SmsQuestionnaireAnalysisOptionResp();
                BeanUtils.copyProperties(option, analysisOptionResp);

                if (topic.getType().equals(TOPIC_TYPE_SELECTION) || topic.getType().equals(TOPIC_TYPE_MULTIPLE)) {
                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId());
                    if (bgDate != null) {
                        queryWrapper.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer optionConfirmCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper);

                    analysisOptionResp.setConfirmCount(optionConfirmCount);
                    double result = ((double) optionConfirmCount / (double) totalOptionCount) * 10;
                    double rate = (double) Math.round(result) / 10;
                    analysisOptionResp.setOptionRate(rate);
                } else if (topic.getType().equals(TOPIC_TYPE_INPUT)) {
                    List<SmsQuestionnaireAnalysisOptionDetailResp> analysisOptionRateRespList = new ArrayList<>();
                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId());
                    if (bgDate != null) {
                        queryWrapper.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    List<SmsQuestionnaireConfirm> confirmList = smsQuestionnaireConfirmMapper.selectList(queryWrapper);
                    if (confirmList != null && confirmList.size() > 0) {
                        StringBuilder totalStr = new StringBuilder();
                        for (SmsQuestionnaireConfirm confirm : confirmList) {
                            if (!isNullOrEmpty(confirm.getOptionContent())) {
                                totalStr.append(confirm.getOptionContent());
                            }
                        }
                        if (!isNullOrEmpty(totalStr.toString())) {
                            JiebaSegmenter jiebaSegmenter = new JiebaSegmenter();
                            List<String> jiebaStr = jiebaSegmenter.sentenceProcess(totalStr.toString());
                            Map<String, Long> resultStr = jiebaStr.stream().filter(str -> str.length() > 1).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
                            if (resultStr.size() > 0) {
                                for (Map.Entry<String, Long> entry : resultStr.entrySet()) {
                                    SmsQuestionnaireAnalysisOptionDetailResp detailResp = new SmsQuestionnaireAnalysisOptionDetailResp();
                                    detailResp.setOptionName(entry.getKey());
                                    detailResp.setOptionCount(entry.getValue().intValue());
                                    analysisOptionRateRespList.add(detailResp);
                                }
                                //排序
                                analysisOptionRateRespList = analysisOptionRateRespList.stream()
                                        .sorted(Comparator.comparingInt(SmsQuestionnaireAnalysisOptionDetailResp::getOptionCount).reversed())
                                        .collect(Collectors.toList());
                                //限制展示数量OPTION_ANALYSIS_INPUT_LIMIT
                                analysisOptionRateRespList = analysisOptionRateRespList.stream().limit(OPTION_ANALYSIS_INPUT_LIMIT).collect(Collectors.toList());
                            }
                        }
                    }
                    analysisOptionResp.setOptionDetailList(analysisOptionRateRespList);
                } else if (topic.getType().equals(TOPIC_TYPE_RATE)) {
                    List<SmsQuestionnaireAnalysisOptionDetailResp> analysisOptionRateRespList = new ArrayList<>();

                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper1 = new QueryWrapper<>();
                    queryWrapper1.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId())
                            .eq(SmsQuestionnaireConfirm::getOptionContent, TOPIC_RATE_ONE_STAR);
                    if (bgDate != null) {
                        queryWrapper1.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper1.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer oneStarCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper1);
                    SmsQuestionnaireAnalysisOptionDetailResp analysisOptionRate1 = new SmsQuestionnaireAnalysisOptionDetailResp();
                    analysisOptionRate1.setOptionName("一星");
                    analysisOptionRate1.setOptionCount(oneStarCount);
                    analysisOptionRate1.setOptionRate(Math.floor(((double) (oneStarCount / totalOptionCount)) * 10) / 10);

                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper2 = new QueryWrapper<>();
                    queryWrapper2.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId())
                            .eq(SmsQuestionnaireConfirm::getOptionContent, TOPIC_RATE_TWO_STAR);
                    if (bgDate != null) {
                        queryWrapper2.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper2.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer twoStarCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper2);
                    SmsQuestionnaireAnalysisOptionDetailResp analysisOptionRate2 = new SmsQuestionnaireAnalysisOptionDetailResp();
                    analysisOptionRate2.setOptionName("二星");
                    analysisOptionRate2.setOptionCount(twoStarCount);
                    analysisOptionRate2.setOptionRate(Math.floor(((double) (twoStarCount / totalOptionCount)) * 10) / 10);

                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper3 = new QueryWrapper<>();
                    queryWrapper3.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId())
                            .eq(SmsQuestionnaireConfirm::getOptionContent, TOPIC_RATE_THREE_STAR);
                    if (bgDate != null) {
                        queryWrapper3.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper3.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer threeStarCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper3);
                    SmsQuestionnaireAnalysisOptionDetailResp analysisOptionRate3 = new SmsQuestionnaireAnalysisOptionDetailResp();
                    analysisOptionRate3.setOptionName("三星");
                    analysisOptionRate3.setOptionCount(threeStarCount);
                    analysisOptionRate3.setOptionRate(Math.floor(((double) (threeStarCount / totalOptionCount)) * 10) / 10);

                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper4 = new QueryWrapper<>();
                    queryWrapper4.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId())
                            .eq(SmsQuestionnaireConfirm::getOptionContent, TOPIC_RATE_FOUR_STAR);
                    if (bgDate != null) {
                        queryWrapper4.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper4.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer fourStarCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper4);
                    SmsQuestionnaireAnalysisOptionDetailResp analysisOptionRate4 = new SmsQuestionnaireAnalysisOptionDetailResp();
                    analysisOptionRate4.setOptionName("四星");
                    analysisOptionRate4.setOptionCount(fourStarCount);
                    analysisOptionRate4.setOptionRate(Math.floor(((double) (fourStarCount / totalOptionCount)) * 10) / 10);

                    QueryWrapper<SmsQuestionnaireConfirm> queryWrapper5 = new QueryWrapper<>();
                    queryWrapper5.lambda()
                            .eq(SmsQuestionnaireConfirm::getOptionId, option.getId())
                            .eq(SmsQuestionnaireConfirm::getOptionContent, TOPIC_RATE_FIVE_STAR);
                    if (bgDate != null) {
                        queryWrapper5.lambda().ge(SmsQuestionnaireConfirm::getCreateTime, bgDate);
                    }
                    if (endDate != null) {
                        queryWrapper5.lambda().le(SmsQuestionnaireConfirm::getCreateTime, endDate);
                    }
                    Integer fiveStarCount = smsQuestionnaireConfirmMapper.selectCount(queryWrapper5);
                    SmsQuestionnaireAnalysisOptionDetailResp analysisOptionRate5 = new SmsQuestionnaireAnalysisOptionDetailResp();
                    analysisOptionRate5.setOptionName("五星");
                    analysisOptionRate5.setOptionCount(fiveStarCount);
                    analysisOptionRate5.setOptionRate(Math.floor(((double) (fiveStarCount / totalOptionCount)) * 10) / 10);

                    analysisOptionRateRespList.add(analysisOptionRate1);
                    analysisOptionRateRespList.add(analysisOptionRate2);
                    analysisOptionRateRespList.add(analysisOptionRate3);
                    analysisOptionRateRespList.add(analysisOptionRate4);
                    analysisOptionRateRespList.add(analysisOptionRate5);

                    analysisOptionResp.setOptionDetailList(analysisOptionRateRespList);
                }
                analysisOptionRespList.add(analysisOptionResp);
            }
            analysisTopicResp.setOptionList(analysisOptionRespList);
            analysisTopicRespList.add(analysisTopicResp);
        }
        smsQuestionnaireAnalysisResp.setAnalysisTopicListList(analysisTopicRespList);
        return CommonResult.success(smsQuestionnaireAnalysisResp);
    }

    @Override
    public ResponseResult getTopicFormDataDetail(String topic_id, List<String> option_id, String name_str,
                                                 String option_str, Integer pageNum, Integer pageSize,
                                                 String bg_date, String end_date) {
        if (isNullOrEmpty(topic_id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsQuestionnaireTopic topic = smsQuestionnaireTopicMapper.selectById(topic_id);
        if (topic == null || topic.getId() == null) {
            return CommonResult.failed(CommonCodeEnum.QUESTIONNAIRE_TOPIC_NOT_EXIST);
        }

        Date bgDate = null;
        Date endDate = null;
        if (!isNullOrEmpty(bg_date)) {
            bgDate = TimeUtil.StringtoDate(bg_date);
        }
        if (!isNullOrEmpty(end_date)) {
            endDate = TimeUtil.StringtoDate(end_date);
        }

        List<SmsUser> userList = smsQuestionnaireAnalysisMapper.getUserIDBySearchStr(null, topic_id, option_id, name_str,
                option_str, pageSize, (pageNum - 1) * pageSize,
                bgDate, endDate);
        List<SmsQuestionnaireAnalysisFormDataDetailResp> formDataDetailRespList = new ArrayList<>();
        if (userList != null && userList.size() > 0) {
            for (SmsUser user : userList) {
                SmsQuestionnaireAnalysisFormDataDetailResp formDataDetailResp = new SmsQuestionnaireAnalysisFormDataDetailResp();
                List<Map<String, Object>> optionList = smsQuestionnaireAnalysisMapper.getOptionNameListByID(topic_id, user.getId());
                List<String> strList;
                if (topic.getType().equals(TOPIC_TYPE_MULTIPLE) || topic.getType().equals(TOPIC_TYPE_SELECTION)) {
                    strList = optionList.stream().map(option -> (String) option.get("option_name")).collect(Collectors.toList());
                } else {
                    strList = optionList.stream().map(option -> (String) option.get("option_content")).collect(Collectors.toList());
                }
                formDataDetailResp.setOptionList(strList);
                formDataDetailResp.setUser_id(user.getId());
                formDataDetailResp.setUser_name(user.getRealName());
                formDataDetailResp.setSubmit_time(user.getCreateTime());
                formDataDetailRespList.add(formDataDetailResp);
            }
        }
        Integer total = smsQuestionnaireAnalysisMapper.getUserIDBySearchStrCount(null, topic_id, option_id, name_str,
                option_str, bgDate, endDate);
        if (total == null) {
            total = 0;
        }
        return CommonResult.success(formDataDetailRespList,total);
    }

    @Override
    public ResponseResult getDataRecord(String ques_id, String user_str, String bg_date,
                                        String end_date, Integer pageNum, Integer pageSize) {
        if (isNullOrEmpty(ques_id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsQuestionnaire smsQuestionnaire = smsQuestionnaireMapper.selectById(ques_id);
        if (smsQuestionnaire == null || smsQuestionnaire.getId() == null) {
            return CommonResult.failed(CommonCodeEnum.QUESTIONNAIRE_NOT_EXIST);
        }

        Date bgDate = null;
        Date endDate = null;
        if (!isNullOrEmpty(bg_date)) {
            bgDate = TimeUtil.StringtoDate(bg_date);
        }
        if (!isNullOrEmpty(end_date)) {
            endDate = TimeUtil.StringtoDate(end_date);
        }
        List<SmsUser> userList = smsQuestionnaireAnalysisMapper.getUserIDBySearchStr(ques_id, null, null,
                user_str, null, pageSize, (pageNum - 1) * pageSize, bgDate, endDate);
        List<SmsUserRecordResp> recordList = userList.stream().map(smsUser -> {
            SmsUserRecordResp recordResp = new SmsUserRecordResp();
            BeanUtils.copyProperties(smsUser, recordResp);
            return recordResp;
        }).collect(Collectors.toList());

        Integer total = smsQuestionnaireAnalysisMapper.getUserIDBySearchStrCount(ques_id, null, null,
                user_str, null, bgDate, endDate);
        if (total == null) {
            total = 0;
        }
        return CommonResult.success(recordList,total);
    }

    @Override
    public ResponseResult getDataRecordDetail(String ques_id, String user_id) {
        if (isNullOrEmpty(ques_id) || isNullOrEmpty(user_id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsQuestionnaire smsQuestionnaire = smsQuestionnaireMapper.selectById(ques_id);
        if (smsQuestionnaire == null || smsQuestionnaire.getId() == null) {
            return CommonResult.failed(CommonCodeEnum.QUESTIONNAIRE_NOT_EXIST);
        }

        List<SmsQuestionnaireTopic> topicList = smsQuestionnaireTopicMapper.selectList(new QueryWrapper<SmsQuestionnaireTopic>()
                .lambda()
                .eq(SmsQuestionnaireTopic::getQuesId, ques_id));

        List<SmsQuestionnaireAnalysisTopicRecordResp> topicRecordList = topicList.stream().map(topic -> {
            SmsQuestionnaireAnalysisTopicRecordResp topicRecord = new SmsQuestionnaireAnalysisTopicRecordResp();
            BeanUtils.copyProperties(topic, topicRecord);

            List<Map<String, Object>> list = smsQuestionnaireAnalysisMapper.getOptionNameListByID(topic.getId(), user_id);

            List<String> strList;
            if (topic.getType().equals(TOPIC_TYPE_MULTIPLE) || topic.getType().equals(TOPIC_TYPE_SELECTION)) {
                strList = list.stream().map(option -> (String) option.get("option_name")).collect(Collectors.toList());
            } else if (topic.getType().equals(TOPIC_TYPE_INPUT)) {
                strList = list.stream().map(option -> (String) option.get("option_content")).collect(Collectors.toList());
            } else {
                strList = list.stream().map(option -> (String) option.get("option_content")).collect(Collectors.toList());
                strList = strList.stream().map(s -> {
                    if (s.equals("1")) {
                        return "一星";
                    } else if (s.equals("2")) {
                        return "二星";
                    } else if (s.equals("3")) {
                        return "三星";
                    } else if (s.equals("4")) {
                        return "四星";
                    }
                    return "五星";
                }).collect(Collectors.toList());
            }
            topicRecord.setOptionList(strList);
            return topicRecord;
        }).collect(Collectors.toList());
        return CommonResult.success(topicRecordList);
    }

}
